/**
 * 给定两个字符串text1 和text2，返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ，返回 0 。
 *
 * 一个字符串的子序列是指这样一个新的字符串：它是由原字符串在不改变字符的相对顺序的情况下删除某些字符（也可以不删除任何字符）后组成的新字符串。
 *
 * 例如，"ace" 是 "abcde" 的子序列，但 "aec" 不是 "abcde" 的子序列。
 * 两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。
 *
 * 链接：https://leetcode.cn/problems/longest-common-subsequence
 *
 */
class LongestCommonSubsequence {
    /**
     * 自底向上的动态规划
     * @param text1
     * @param text2
     * @return
     */
     public int longestCommonSubsequence(String text1, String text2) {
        int n=text1.length();
        int m=text2.length();
        int[][] dp=new int[n+1][m+1];
        for(int i=1;i<=n;i++) {
            for(int j=1;j<=m;j++) {
                if(text1.charAt(i-1)==text2.charAt(j-1)) {
                    dp[i][j]=1+dp[i-1][j-1];
                } else {
                    dp[i][j]=Math.max(dp[i][j-1],dp[i-1][j]);
                }
            }
        }
        return dp[n][m];
    }

    /**
     * 自顶向下的动态规划
     */
    int[][] memo;
    public int longestCommonSubsequenceDpMemo(String text1, String text2) {
        int n=text1.length();
        int m=text2.length();
        memo=new int[n][m];
        for(int[] row:memo) {
            Arrays.fill(row,-1);
        }
        return dp(text1,0,text2,0);
    }
    public int dp(String s1,int i,String s2,int j) {
        if(i==s1.length()||j==s2.length()) {
            return 0;
        }
        if(memo[i][j]!=-1) {
            return memo[i][j];
        }
        if(s1.charAt(i)==s2.charAt(j)) {//两个字母相等是公共子序列
            memo[i][j]=1+dp(s1,i+1,s2,j+1);
        }
        else {
            memo[i][j]=Math.max(
                        dp(s1,i+1,s2,j),//s1所指的这个字母没在公共子序列中
                        dp(s1,i,s2,j+1)//s2所指的这个字母没在公共子序列中
            );
        }
        return memo[i][j];
    }
}